package org.exhibitj.elements;

import java.awt.AWTException;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;

import junit.framework.Assert;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class ExploringSWTBehavior {
	Display display;
	private static boolean[] clickeds;
	private Robot robot;

	public static void main(String[] args) throws Exception {
		ExploringSWTBehavior behavior = new ExploringSWTBehavior();
		behavior.openShell();

		behavior.doubleClickMouseInsideWidget("dopey");
		behavior.enterKeysOnKeyboard("hello");
		behavior.clickMouseInsideWidget("bashful");
		Assert.assertTrue(clickeds[0]);
	}

	private void enterKeysOnKeyboard(final String textToEnter) {
		Display.getDefault().syncExec(new Runnable() {

			@Override
			public void run() {
				robot.keyPress(KeyEvent.VK_SHIFT);
				robot.keyPress(KeyEvent.VK_H);
				robot.delay(50);
				robot.keyRelease(KeyEvent.VK_H);
				robot.keyRelease(KeyEvent.VK_SHIFT);

				robot.keyPress(KeyEvent.VK_E);
				robot.delay(50);
				robot.keyRelease(KeyEvent.VK_E);
				
				robot.keyPress(KeyEvent.VK_L);
				robot.delay(50);
				robot.keyRelease(KeyEvent.VK_L);
				
				robot.keyPress(KeyEvent.VK_L);
				robot.delay(50);
				robot.keyRelease(KeyEvent.VK_L);
				
				robot.keyPress(KeyEvent.VK_O);
				robot.delay(50);
				robot.keyRelease(KeyEvent.VK_O);
			}
		});
		Display.getDefault().syncExec(new Runnable() {

			@Override
			public void run() {

			}
		});
	}

	private void doubleClickMouseInsideWidget(final String widgetName) {
		Display.getDefault().syncExec(new Runnable() {

			@Override
			public void run() {
				Shell shell = display.getShells()[0];
				for (Control each : shell.getChildren()) {
					Object data = each.getData("name");
					if (data != null && data.equals(widgetName)) {
						doubleClickInside(each);
					}
				}
			}
		});
		Display.getDefault().syncExec(new Runnable() {

			@Override
			public void run() {
			}
		});
	}
	
	private void clickMouseInsideWidget(final String widgetName) {
		Display.getDefault().syncExec(new Runnable() {

			@Override
			public void run() {
				Shell shell = display.getShells()[0];
				for (Control each : shell.getChildren()) {
					Object data = each.getData("name");
					if (data != null && data.equals(widgetName)) {
						clickInside(each);
					}
				}
			}
		});
		Display.getDefault().syncExec(null);
	}
	
	private void openShell() throws Exception {
		new Thread(new Runnable() {

			@Override
			public void run() {
				display = new Display();
				final Shell shell = new Shell(display);
				shell.setSize(500, 500);
				final Button button = new Button(shell, SWT.PUSH);
				button.setLocation(50, 50);
				button.setText("hit me!");
				button.pack();
				clickeds = new boolean[] { false };

				Text textField = new Text(shell, SWT.SINGLE);
				textField.setLocation(50, 100);
				textField.setText("ok great!");
				textField.pack();
				button.addSelectionListener(new SelectionListener() {

					@Override
					public void widgetSelected(SelectionEvent e) {
						button.setText("gotcha");
						clickeds[0] = true;
					}

					@Override
					public void widgetDefaultSelected(SelectionEvent e) {
						clickeds[0] = true;
					}
				});
				button.setData("name", "bashful");
				textField.setData("name", "dopey");
				shell.open();
				while (!shell.isDisposed()) {
					if (!display.readAndDispatch())
						display.sleep();
				}
				display.dispose();
			}
		}).start();
		while (display == null) {
			Thread.sleep(5);
		}
	}
	
	private void doubleClickInside(Control control) {
		initRobot();
		
		moveMouseToLocation(control);
		
		robot.setAutoWaitForIdle(true);
		doubleLeftClickOnMouse();
	}

	private void doubleLeftClickOnMouse() {
		leftClickOnMouse();
		robot.delay(display.getDoubleClickTime());
		leftClickOnMouse();
	}

	private void leftClickOnMouse() {
		robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
		robot.delay(1000);
		robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
	}

	private void moveMouseToLocation(Control control) {
		Rectangle bounds = control.getBounds();
		int x = bounds.width / 2 + control.getBorderWidth() + 0;
		int y = bounds.height / 2 + control.getBorderWidth() + 23; // display.titleTrimWidth;
		while (control != null) {
			bounds = control.getBounds();
			x += bounds.x + control.getBorderWidth();
			y += bounds.y + control.getBorderWidth();
			control = control.getParent();
		}
		Point location = new Point(x, y);
		while (true) {
			Point currentLocation = MouseInfo.getPointerInfo().getLocation();

			if (currentLocation.equals(location)) {
				break;
			}

			currentLocation.x += (currentLocation.x > x) ? -1 : currentLocation.x < x ? +1 : 0;
			currentLocation.y += (currentLocation.y > y) ? -1 : currentLocation.y < y ? +1 : 0;
			robot.mouseMove(currentLocation.x, location.y);
			robot.delay(1);
		}
	}

	private void clickInside(Control control) {
		initRobot();
		moveMouseToLocation(control);
		robot.setAutoWaitForIdle(true);
		leftClickOnMouse();
	}

	private void initRobot() {
		if (robot == null) {
			try {
				robot = new Robot();
			} catch (AWTException e) {
				e.printStackTrace();
			}
		}
	}
}
